package worker

import (
	"common/util/process"
	"sync"
	"time"
)

type instance interface {
	IsFree() bool
	Id() string
	SetId(id string)
	Reset()
	Scan()
}

// Manager 实例管理.
type Manager struct {
	// insts *mem.ChannelBuf
	store []instance

	active    int // 当前已经分配的实例数.
	capacity  int //
	selectKey int

	sync.RWMutex
}

// 实例sessions和room分别管理.
var sessionManager *Manager
var roomManager *Manager

// InitManager 只管实例的管理，实例初始化不管.
// 目前sessions和rooms数量采用同样的数量，
func InitManager(start, capacity int) {
	if sessionManager == nil {
		// 初始化端口分配器
		// InitPortSuiteHelper(start, capacity)

		// 初始化会话管理器
		sessionManager = &Manager{store: make([]instance, capacity)}

		for index, _ := range sessionManager.store {
			session := &Session{}
			sessionManager.store[index] = session
		}

		// 启动会话过期扫描
		go sessionManager.scanOutDate()
	}

	if roomManager == nil {
		// 初始化会话管理器
		roomManager = &Manager{store: make([]instance, capacity)}
		for index, _ := range roomManager.store {
			room := &Room{}
			roomManager.store[index] = room
		}

		// 启动会话过期扫描
		go roomManager.scanOutDate()
	}
}

func GetSessionManager() *Manager {
	return sessionManager
}

func GetRoomManager() *Manager {
	return roomManager
}

// GetFree session实例的管理
func (m *Manager) GetFree(sessionId string) instance {
	if len(sessionId) == 0 {
		return nil
	}

	m.Lock()
	defer m.Unlock()
	if m.selectKey >= len(m.store) {
		m.selectKey = 0
	}
	for i := m.selectKey; i < len(m.store); i++ {
		if m.store[i] == nil {
			// 端口逻辑外部分配.
			//port, _ := Allocated()
			//m.store[i] = m.new(port)
			m.store[i].SetId(sessionId)
			m.active++
			m.selectKey = i + 1
			return m.store[i]
		}
		if m.store[i].IsFree() {
			m.store[i].Reset()
			m.store[i].SetId(sessionId)
			m.active++
			m.selectKey = i + 1
			return m.store[i]
		}
	}
	for i := 0; i < m.selectKey; i++ {
		if m.store[i] == nil {
			// 端口逻辑外部分配.
			//port, _ := Allocated()
			//m.store[i] = m.new(port)
			m.store[i].SetId(sessionId)
			m.active++
			m.selectKey = i + 1
			return m.store[i]
		}
		if m.store[i].IsFree() {
			m.store[i].Reset()
			m.store[i].SetId(sessionId)
			m.active++
			m.selectKey = i + 1
			return m.store[i]
		}
	}
	return nil
}

func (m *Manager) Get(id string) (instance, bool) {
	if len(id) == 0 {
		return nil, false
	}

	m.RLock()
	defer m.RUnlock()
	for _, session := range m.store {
		if session != nil && session.Id() == id {
			return session, true
		}
	}
	return nil, false
}

func (m *Manager) Free(id string) {
	if len(id) == 0 {
		return
	}

	m.Lock()
	defer m.Unlock()
	for _, session := range m.store {
		if session != nil && session.Id() == id {
			session.SetId("")
			m.active--
			return
		}
	}
}

// GetFreeRoom room实例的管理

func (m *Manager) Stop() {
	t := time.NewTicker(time.Second)
	for {
		select {
		case <-t.C:
			isAllFree := true
			for _, session := range m.store {
				if session != nil && !session.IsFree() {
					isAllFree = false
					break
				}
			}
			if isAllFree {
				return
			}
		}
	}
}

func (m *Manager) scanOutDate() {
	defer func() {
		if err := recover(); err != nil {
			process.DefaultPanicReport.RecoverFromPanic("", "ScanOutDate", err)
		}
	}()

	t := time.NewTicker(time.Minute * 5)
	for {
		select {
		case <-t.C:
			// get call counts
			// here must move to the record file function
			// re-calculate to modify total count considering bugs
			m.RLock()
			size := 0
			for _, session := range m.store {
				if session != nil && !session.IsFree() {
					size++
				}
			}
			m.active = size
			m.RUnlock()

			for _, session := range m.store {
				if session == nil || session.IsFree() {
					continue
				}
				session.Scan()
			}
		}
	}
}
